/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jena.rdf.model.test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.test.helpers.ModelHelper;
import org.apache.jena.rdf.model.test.helpers.TestingModelFactory;
import org.apache.jena.shared.PropertyNotFoundException;
import org.apache.jena.test.JenaTestBase;
import org.apache.jena.util.iterator.WrappedIterator;
import org.apache.jena.vocabulary.RDF;
import org.junit.Assert;

public class TestListSubjects extends AbstractModelTestBase {

    static final String subjectPrefix = "http://aldabaran/test8/s";

    static final String predicatePrefix = "http://aldabaran/test8/";

    Resource[] subjects;

    Property[] predicates;

    RDFNode[] objects;
    // Literal [] tvLitObjs;
    Resource[] tvResObjs;
    boolean[] tvBooleans = {false, true};
    long[] tvLongs = {123, 321};

    char[] tvChars = {'@', ';'};
    float[] tvFloats = {456.789f, 789.456f};
    double[] tvDoubles = {123.456, 456.123};
    String[] tvStrings = {"test8 testing string 1", "test8 testing string 2"};
    String[] langs = {"en", "fr"};

    public TestListSubjects(final TestingModelFactory modelFactory, final String name) {
        super(modelFactory, name);
    }

    protected void assertEquiv(final Set<? extends Resource> set, final Iterator<? extends Resource> iterator) {
        final List<? extends Resource> L = WrappedIterator.create(iterator).toList();
        Assert.assertEquals(set.size(), L.size());
        Assert.assertEquals(set, new HashSet<>(L));
    }

    protected void fillModel() {
        final int num = 5;
        // tvLitObjs = new Literal[]
        // { model.createTypedLiteral( new LitTestObjF() ),
        // model.createTypedLiteral( new LitTestObjF() ) };

        // tvResObjs = new Resource[]
        // { model.createResource( new ResTestObjF() ),
        // model.createResource( new ResTestObjF() ) };

        objects = new RDFNode[]{model.createTypedLiteral(tvBooleans[1]), model.createTypedLiteral(tvLongs[1]),
            model.createTypedLiteral(tvChars[1]), model.createTypedLiteral(tvFloats[1]), model.createTypedLiteral(tvDoubles[1]),
            model.createLiteral(tvStrings[1]), model.createLiteral(tvStrings[1], langs[1])
            // tvLitObjs[1],
            // tvResObjs[1]
        };

        subjects = new Resource[num];
        predicates = new Property[num];

        for ( int i = 0 ; i < num ; i++ ) {
            subjects[i] = model.createResource(TestListSubjects.subjectPrefix + i);
            predicates[i] = model.createProperty(TestListSubjects.predicatePrefix + i, "p");
        }

        for ( int i = 0 ; i < num ; i += 1 ) {
            model.addLiteral(subjects[i], predicates[4], false);
        }

        for ( int i = 0 ; i < 2 ; i += 1 ) {
            for ( int j = 0 ; j < 2 ; j += 1 ) {
                model.add(subjects[i], predicates[j], model.createTypedLiteral(tvBooleans[j]));
                model.addLiteral(subjects[i], predicates[j], tvLongs[j]);
                model.addLiteral(subjects[i], predicates[j], tvChars[j]);
                model.add(subjects[i], predicates[j], model.createTypedLiteral(tvFloats[j]));
                model.add(subjects[i], predicates[j], model.createTypedLiteral(tvDoubles[j]));
                model.add(subjects[i], predicates[j], tvStrings[j]);
                model.add(subjects[i], predicates[j], tvStrings[j], langs[j]);
                // model.add(subjects[i], predicates[j], tvLitObjs[j] );
                // model.add(subjects[i], predicates[j], tvResObjs[j] );
            }
        }
    }

    // the methods are deprecated, the tests eliminated
    // public void testListResourcesOnObject()
    // {
    // Object d = new Date();
    // Model model = modelWithStatements( "" );
    // model.addLiteral( resource( "S" ), property( "P" ), d );
    // model.addLiteral( resource( "X" ), property( "P" ), new Object() );
    // List answers = model.listResourcesWithProperty( property( "P" ), d
    // ).toList();
    // assertEquals( listOfOne( resource( "S" ) ), answers );
    // }

    @Override
    public void setUp() {
        super.setUp();
        fillModel();
    }

    protected Set<Resource> subjectsTo(final String prefix, final int limit) {
        final Set<Resource> result = new HashSet<>();
        for ( int i = 0 ; i < limit ; i += 1 ) {
            result.add(ModelHelper.resource(prefix + i));
        }
        return result;
    }

    public void testGetRequiredProperty() {
        model.getRequiredProperty(subjects[1], predicates[1]);
        try {
            model.getRequiredProperty(subjects[1], RDF.value);
            Assert.fail("should not find absent property");
        } catch (final PropertyNotFoundException e) {
            JenaTestBase.pass();
        }
    }

    public void testListSubjects() {
        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 5), model.listResourcesWithProperty(predicates[4]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], tvBooleans[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], tvBooleans[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], tvChars[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], tvChars[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], tvLongs[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], tvLongs[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], tvFloats[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], tvFloats[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], tvDoubles[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], tvDoubles[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], (byte)tvLongs[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], (byte)tvLongs[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], (short)tvLongs[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], (short)tvLongs[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listResourcesWithProperty(predicates[0], (int)tvLongs[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listResourcesWithProperty(predicates[0], (int)tvLongs[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listSubjectsWithProperty(predicates[0], tvStrings[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listSubjectsWithProperty(predicates[0], tvStrings[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 2), model.listSubjectsWithProperty(predicates[0], tvStrings[0], langs[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listSubjectsWithProperty(predicates[0], tvStrings[1], langs[0]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listSubjectsWithProperty(predicates[0], tvStrings[0], langs[1]));

        assertEquiv(subjectsTo(TestListSubjects.subjectPrefix, 0), model.listSubjectsWithProperty(predicates[0], tvStrings[1], langs[1]));

        // assertEquiv( subjectsTo( subjectPrefix, 2 ),
        // model.listResourcesWithProperty( predicates[0], tvLitObjs[0] ) );
        //
        // assertEquiv( subjectsTo( subjectPrefix, 0 ),
        // model.listResourcesWithProperty( predicates[0], tvLitObjs[1] ) );
        //
        // assertEquiv( subjectsTo( subjectPrefix, 0 ),
        // model.listResourcesWithProperty( predicates[0], tvResObjs[0] ) );
        //
        // assertEquiv( subjectsTo( subjectPrefix, 0 ),
        // model.listResourcesWithProperty( predicates[0], tvResObjs[1] ) );

        // assertEquiv( new HashSet( Arrays.asList( objects ) ),
        // model.listObjectsOfProperty( predicates[1] ) );
    }
}
